<template>
  <div ref="tabBox" class="tab-box">
    <div
      v-for="(tab, index) in tabs"
      :key="tab.id"
      class="tab-item"
      :class="{
        active: tab.id === modelValue,
        dragging: draggingIndex === index
      }"
      @mousedown.stop="startDrag($event, index, tab)"
    >
      <span>{{ tab.label }}</span>
      <span @click.stop="closeBtn(tab)" class="close_btn" v-if="!drageStatus">
        <el-icon><Close /></el-icon>
      </span>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { ref, onBeforeUnmount, defineEmits, defineProps, computed, nextTick } from 'vue'
import { Close } from '@element-plus/icons-vue';
import { useMenuStore } from '../stores/menusStore';

interface Tab {
  id: string | number
  label: string
}

const props = defineProps<{
  tabs: Tab[]
  modelValue: string | number | null
}>()

const emit = defineEmits<{
  (e: 'update:tabs', value: Tab[]): void
  (e: 'exceed', tab: Tab): void
  (e: 'update:modelValue', value: string | number): void
  (e: 'change', tab: Tab): void
  (e: 'closeBtn', tab: Tab): void
}>()

const menuStore = useMenuStore();
const tabBox = ref<HTMLElement | null>(null)
const draggingIndex = ref<number | null>(null)
const startX = ref(0)
const startY = ref(0)
const originalIndex = ref(-1)
const offsetX = ref(0)
const originalTop = ref(0)
const placeholder = ref<HTMLElement | null>(null)
const draggedTab = ref<Tab | null>(null)
const triggeredExceed = ref(false)
const tabPositions = ref<{ [key: number]: number }>({})

const drageStatus = ref(false);

const activeIndex = computed(() =>
  props.tabs.findIndex(tab => tab.id === props.modelValue)
)

function selectTab(tab: Tab) {
  if (tab.id !== props.modelValue) {
    emit('change', tab)
    emit('update:modelValue', tab.id)
  }
}

function closeBtn(tab: Tab) {
  emit('closeBtn', tab)
}

function recordTabPositions() {
  if (!tabBox.value) return
  const positions: { [key: number]: number } = {}
  const tabElements = tabBox.value.querySelectorAll('.tab-item')
  tabElements.forEach((el, index) => {
    positions[index] = (el as HTMLElement).offsetLeft
  })
  tabPositions.value = positions
}

// 应用挤开动画
function applyTabAnimations() {
  if (!tabBox.value || !Object.keys(tabPositions.value).length) return;

  const tabElements = tabBox.value.querySelectorAll('.tab-item');

  tabElements.forEach((el, index) => {
    if (index !== draggingIndex.value && tabPositions.value[index] !== undefined) {
      const element = el as HTMLElement;
      const currentLeft = element.offsetLeft;
      const originalLeft = tabPositions.value[index];
      const diff = originalLeft - currentLeft;

      if (diff !== 0) {
        // 1. 先回到旧位置
        element.style.transform = `translateX(${diff}px)`;
        // 2. 下一帧再过渡到 0
        setTimeout((() => {
          element.style.transition= `transform 0.3s ease, background 0.2s`;
          element.style.transform = 'translateX(0)';
          setTimeout(() => {
            element.style.transition= ``;
          }, 300)
        }), 50)
      }
    }
  });
}

function startDrag(e: MouseEvent, index: number, tab: any) {
  drageStatus.value=true;
  selectTab(tab)
  const tabElement = e.currentTarget as HTMLElement

  if (props.tabs.length <= 1) {
    return drageStatus.value = false;
  } 
  originalIndex.value = index
  draggedTab.value = props.tabs[index]
  draggingIndex.value = index
  startX.value = e.clientX
  startY.value = e.clientY

  const rect = tabElement.getBoundingClientRect()
  offsetX.value = e.clientX - rect.left
  originalTop.value = rect.top

  recordTabPositions()
  createPlaceholder(tabElement)

  document.addEventListener('mousemove', handleDrag)
  document.addEventListener('mouseup', handleDragEnd)
  e.preventDefault()
}

function createPlaceholder(originalElement: HTMLElement) {
  if (placeholder.value) return
  const width = originalElement.offsetWidth;
  console.log(width);
  const height = originalElement.offsetHeight;
  placeholder.value = document.createElement('div')
  // placeholder.value.className = 'tab-placeholder'
  // placeholder.value.style.width = `${originalElement.offsetWidth}px`
  // placeholder.value.style.height = `${originalElement.offsetHeight}px`

  placeholder.value.className = 'tab-placeholder'
  placeholder.value.style.width = `${originalElement.offsetWidth}px`
  placeholder.value.style.height = `${originalElement.offsetHeight}px`

  const parent = originalElement.parentElement
  if (parent) {
    parent.insertBefore(placeholder.value, originalElement)
    originalElement.style.position = 'fixed'
    originalElement.style.width = `${width}px`
    originalElement.style.height = `${height}px`
    originalElement.style.zIndex = '1000';
    originalElement.style.boxSizing = 'border-box'
    updateDraggedElementPosition(startX.value, startY.value)
  }
}

function updateDraggedElementPosition(clientX: number, clientY: number) {
  if (!tabBox.value || draggingIndex.value === null) return
  const tabElements = tabBox.value.querySelectorAll('.tab-item')
  const draggedElement = tabElements[draggingIndex.value] as HTMLElement
  if (draggedElement) {
    draggedElement.style.left = `${clientX - offsetX.value}px`
    draggedElement.style.top = `${originalTop.value}px`
  }
}

function handleDrag(e: MouseEvent) {
  if (draggingIndex.value === null || !draggedTab.value || !tabBox.value) return
  updateDraggedElementPosition(e.clientX, e.clientY)
  checkExceed(e)
  if (triggeredExceed.value) return
  handleReordering(e)
}

function checkExceed(e: MouseEvent) {
  if (!tabBox.value || !draggedTab.value || triggeredExceed.value) return
  const threshold = 30
  const box = tabBox.value.getBoundingClientRect()
  const isOutside =
    e.clientX < box.left - threshold ||
    e.clientX > box.right + threshold ||
    e.clientY < box.top - threshold ||
    e.clientY > box.bottom + threshold
  if (isOutside) {
    triggeredExceed.value = true
    drageStatus.value=false;
    emit('exceed', draggedTab.value)
    handleDragEnd(true);
  }
}

function handleReordering(e: MouseEvent) {
  if (!tabBox.value || !placeholder.value) return
  const tabElements = Array.from(
    tabBox.value.querySelectorAll('.tab-item:not(.dragging)')
  )
  if (!tabElements.length) return

  // 找到距离鼠标最近的 tab
  let closestTab = null
  let minDistance = Infinity

  tabElements.forEach(el => {
    const rect = el.getBoundingClientRect()
    const center = rect.left + rect.width / 2
    const distance = Math.abs(e.clientX - center)
    if (distance < minDistance) {
      minDistance = distance
      closestTab = el
    }
  })

  if (closestTab) {
    const rect = closestTab.getBoundingClientRect()
    const isBefore = e.clientX < rect.left + rect.width / 2
    const parent = placeholder.value.parentElement
    if (parent) {
      recordTabPositions()
      if (isBefore) {
        parent.insertBefore(placeholder.value, closestTab)
      } else {
        parent.insertBefore(placeholder.value, closestTab.nextSibling)
      }
      nextTick(() => {
        applyTabAnimations()
      })
    }
  }
}

function handleDragEnd(params:Boolean = false) {
  if (draggingIndex.value === null || !tabBox.value || !draggedTab.value) return
  const tabElements = tabBox.value.querySelectorAll('.tab-item')
  const draggedElement = tabElements[draggingIndex.value] as HTMLElement
  if (draggedElement) {
    draggedElement.style.position = ''
    draggedElement.style.left = ''
    draggedElement.style.top = ''
    draggedElement.style.width = ''
    draggedElement.style.zIndex = ''
  }

  let newIndex = -1
  if (placeholder.value && placeholder.value.parentElement) {
    const children = Array.from(placeholder.value.parentElement.children)
    newIndex = children.indexOf(placeholder.value)
    placeholder.value.parentElement.removeChild(placeholder.value)
    placeholder.value = null
  }

  if (!triggeredExceed.value && originalIndex.value !== -1 && newIndex !== -1 && newIndex !== originalIndex.value) {
    const newTabs = [...props.tabs]
    const [movedTab] = newTabs.splice(originalIndex.value, 1)
    newTabs.splice(newIndex, 0, movedTab)
    emit('update:tabs', newTabs)
  }

  draggingIndex.value = null
  originalIndex.value = -1
  draggedTab.value = null
  triggeredExceed.value = false
  tabPositions.value = {}
  drageStatus.value = false;

  document.removeEventListener('mousemove', handleDrag)
  document.removeEventListener('mouseup', handleDragEnd)

  // 如果是新窗口导致的拖拽结束，需要继续监听mouseup事件
  document.addEventListener('mouseup', () => {
    window.ipcRenderer.send('mouse-up');
  })
}

onBeforeUnmount(() => {
  document.removeEventListener('mousemove', handleDrag)
  document.removeEventListener('mouseup', handleDragEnd)
})
</script>

<style scoped>
.tab-box {
  display: flex;
  padding: 8px;
  gap: 5px;
  max-width: calc(100vw - 300px);
  overflow-x: auto;
  position: relative;
}

.tab-item {
  padding: 5px 6px;
  border-radius: 6px;
  user-select: none;
  font-size: 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex: 0 1 100px;
  width: 100px;
  text-align: center;
  white-space: nowrap;
  text-overflow: ellipsis;
  position: relative;
  box-sizing: border-box;
}

.tab-item.dragging {
  opacity: 0.8;
  cursor: grabbing;
  pointer-events: none;
  transition: none;
}

.tab-placeholder {
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.1);
  flex: 0 1 100px;
}

.tab-item .close_btn {
  transform: translateY(2px);
  color: transparent;
  cursor: pointer;
  margin-left: 5px;
  transition: color 0.2s;
}

.tab-item:hover {
  background: rgba(255, 255, 255, 0.1);
}

.tab-item:hover .close_btn {
  color: #fff;
}

.tab-item.active {
  background: rgba(255, 255, 255, 0.15);
  color: #fff;
}

.tab-item:active {
  cursor: grabbing;
}

.drag-tab {
  -webkit-app-region: drag;
}
</style>
